/**
	ETFAna project, Anyang Normal University && IMP-CAS
  \class ETFExpData
  \brief error propagation
	\author SUN Yazhou, asia.rabbit@163.com
  \since 2022-05-23
  \date 2022-06-24 last modified
  \attention
  changelog
  <table>
  <tr>  <th>Date         <th>Author      <th>Description                   </tr>
  <tr>  <td>2022-05-23   <td>Asia Sun    <td>file created                  </tr>
  </table>

  \copyright Copyright (c) 2021-2024 Anyang Normal U. && IMP-CAS with LGPLv3 LICENSE
*/

#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <cmath>
#include "ETFExpData.h"

using std::cout;
using std::endl;

ETFExpData::ETFExpData(double val, double err) : fVal(val), fErr(err){}
ETFExpData::ETFExpData(const ETFExpData &data){ *this = data; }
ETFExpData &ETFExpData::operator=(const ETFExpData &data){
	if(&data == this) return *this;

	fVal = data.fVal;
	fErr = data.fErr;

	return *this;
} // end member function operator=

void ETFExpData::print() const{
	cout << std::fixed;
	cout << std::setprecision(4);
	const double rel = fErr / fVal * 100.;
	cout << fVal << "(" << fErr << ", " << rel << "%)";
} // end member function Print
std::ostream &operator<<(std::ostream &os, const ETFExpData &data){
	// os << data.fVal;
	const double rel = data.fErr / data.fVal * 100.;
	os << data.fVal << "(" << data.fErr << ", " << rel << "%)";
	return os;
} // end member function operator<<
const ETFExpData &ETFExpData::operator+=(const ETFExpData &data){
	fVal += data.fVal;
	fErr = sqrt(fErr*fErr + data.fErr*data.fErr);

	return *this;
} // end member function operator+=
const ETFExpData &ETFExpData::operator-=(const ETFExpData &data){
	fVal -= data.fVal;
	fErr = sqrt(fErr*fErr + data.fErr*data.fErr);

	return *this;
} // end member function operator-=
const ETFExpData &ETFExpData::operator*=(const ETFExpData &data){
	const double prod = fVal*data.fVal;
	fErr = sqrt(pow(fErr*data.fVal, 2) + pow(data.fErr*fVal, 2));
//	fErr = fabs(prod)*sqrt(pow(fErr/fVal, 2) + pow(data.fErr/data.fVal, 2));
	fVal = prod;

	return *this;
} // end member function operator*=
const ETFExpData &ETFExpData::operator/=(const ETFExpData &data){
	const double rate = fVal/data.fVal;
	fErr = fabs(rate)*sqrt(pow(fErr/fVal, 2) + pow(data.fErr/data.fVal, 2));
	fVal = rate;

	return *this;
} // end member function operator/=
ETFExpData ETFExpData::operator+(const ETFExpData &data) const{
	return ETFExpData(*this) += data;
} // end member function operator+
ETFExpData ETFExpData::operator-(const ETFExpData &data) const{
	return ETFExpData(*this) -= data;
} // end member function operator-
ETFExpData ETFExpData::operator*(const ETFExpData &data) const{
	return ETFExpData(*this) *= data;
} // end member function operator*
ETFExpData ETFExpData::operator/(const ETFExpData &data) const{
	return ETFExpData(*this) /= data;
} // end member function operator/

ETFExpData Sqrt(const ETFExpData &p){
	const double val = sqrt(p.val());
	const double err = p.err() / (2.*val);
	return ETFExpData(val, err);
} // end member function Sqrt
ETFExpData Log(const ETFExpData &p){
	const double val = log(p.val());
	const double err = p.err() / p.val();
	return ETFExpData(val, err);
} // end member function Log
ETFExpData operator+(double x, const ETFExpData &p){
	return ETFExpData(x+p.val(), p.err());
} // end member function operator+
ETFExpData operator-(double x, const ETFExpData &p){
	return ETFExpData(x-p.val(), p.err());
} // end member function operator-
ETFExpData Exp(const ETFExpData &p){
	const double ep = exp(p.val());
	return ETFExpData(ep, ep*p.err());
} // end member function Exp

ETFExpData operator*(double k, const ETFExpData &data){
	return data*ETFExpData(k, 0.);
} // end member function operator*

ETFExpData operator/(double k, const ETFExpData &data){
	return data/ETFExpData(k, 0.);
} // end member function operator/
